/***************************************************************************
 *   Copyright (C) 2007 by Leonid Krashenko   *
 *   Leonid.Krashenko@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "todolist.h"
#include "todoitem.h"
#include "frmedittask.h"
#include "taskcreatedlg.h"

#include <qlistview.h>
#include <qpushbutton.h>
#include <qdragobject.h>
#include <qlayout.h>
#include <qfile.h>
#include <qmessagebox.h>
#include <qevent.h>

ToDoList::ToDoList(QWidget* parent, const char* name)
 : QListView(parent, name)
{
	init();
}

// ToDoList::~ToDoList()
// {
// }

void ToDoList::init()
{
//	QVBoxLayout* vbox = new QVBoxLayout(this);
//	vbox->setAlignment(AlignTop);
//	QPushButton* btn = new QPushButton("hello", this, "hello");
//	vbox->addWidget(btn);
	
//	_lstToDo = new QListView(this, "ToDoList");
//	_lstToDo->setMultiSelection(false);
	setMultiSelection(false);
	
//	vbox->addWidget(_lstToDo);
	
	addColumn("Task");
	addColumn("%");
	addColumn("!");
	
	_itemCounter = 0;
	_dropItem = 0;
	_bufferedItem = 0;
	_lastOperation = None;
	
	connect ( this, SIGNAL(itemRenamed(QListViewItem*, int, const QString&)), this, SLOT(itemRenamed(QListViewItem*, int, const QString&)) );
	connect ( this, SIGNAL(spacePressed(QListViewItem*)), this, SLOT(spacePressed(QListViewItem*)) );
	connect ( this, SIGNAL(returnPressed(QListViewItem*)), this, SLOT(editTask(QListViewItem*)) );
	connect ( this, SIGNAL(doubleClicked(QListViewItem *, const QPoint &, int)), SLOT(itemDoubleClicked(QListViewItem *, const QPoint &, int)) );
	connect ( this, SIGNAL(clicked(QListViewItem *, const QPoint &, int)),  SLOT(itemClicked(QListViewItem *, const QPoint &, int)) );
			
	//_lstToDo->setCurrentItem(_lstToDo->firstChild());
	setCurrentItem(firstChild());
	
	setColumnWidthMode(0, QListView::Maximum);
	setResizeMode(QListView::LastColumn);
	
	setAcceptDrops(TRUE);
	viewport()->setAcceptDrops(TRUE);
	
	setRootIsDecorated(true);
}

void ToDoList::itemDoubleClicked(QListViewItem *item, const QPoint &, int)
{
	editTask(item);
}

void ToDoList::itemClicked(QListViewItem *item, const QPoint &, int c)
{
/*	ToDoItem* todoItem = this->selectedItem();
	QCheckListItem::ToggleState state = todoItem->state();

	if(state!=QCheckListItem::NoChange)
	{
		todoItem->completeChildren(todoItem->isOn());
		todoItem->updateToRoot();
	}*/
}

void ToDoList::itemRenamed(QListViewItem* item, int col, const QString& text)
{
	ToDoItem* todoItem = dynamic_cast<ToDoItem*>(item);
	
	if(todoItem == 0)	
		return;
	
//	QMessageBox::information(0,text, text);
	todoItem->setName(text);
}

void ToDoList::addAdvancedItem()
{
	TaskCreateDlg* taskCreateDlg = new TaskCreateDlg;
	taskCreateDlg->exec();
	delete taskCreateDlg;

	//addItem();
}

void ToDoList::addItem()
{
	ToDoItem::stateChanging = true;
	QListViewItem* selectedItem = this->selectedItem();
	ToDoItem* todoItem;
			
	if(selectedItem == 0){
		todoItem = new ToDoItem(this, QString("task")+QString::number(_itemCounter));
		insertItem(todoItem);
	}
	else {
		todoItem = new ToDoItem(selectedItem, QString("task")+QString::number(_itemCounter));
		selectedItem->insertItem(todoItem);
//		((ToDoItem*)selectedItem)->calculateParams();
//		todoItem->calculateParams();
	}
	
	todoItem->updateToRoot();
	
	todoItem->setRenameEnabled(0, true);
	
	setCurrentItem(todoItem);
	_itemCounter++;
	ToDoItem::stateChanging = false;
}

void ToDoList::deleteItem()
{
	ToDoItem *item = selectedItem();
	
	if(!item)
		return;
	
	ToDoItem::stateChanging = true;
	
	QListViewItem* sibling = item->nextSibling();
	ToDoItem* parent = (ToDoItem*)item->parent();
	
	delete item;
	
	if(sibling)
		sibling->setSelected(true);
	
	if(parent){
		parent->calculateParams();
		parent->updateToRoot();
	}
	
	ToDoItem::stateChanging = false;
}

void ToDoList::addChildItem()
{
	QListViewItem* selectedItem = this->selectedItem();
	if(selectedItem == 0)
		return;
	
	ToDoItem* todoItem = new ToDoItem(selectedItem, QString("task")+QString::number(_itemCounter));
	todoItem->setRenameEnabled(0, true);
	
//	selectedItem->setCurrentItem()
	_itemCounter++;
}

void ToDoList::incCompletion()
{
	ToDoItem* selectedItem = this->selectedItem();
	if(selectedItem == 0)
		return;
	
	selectedItem->increaseCompletion(1);
}

void ToDoList::decCompletion()
{
	ToDoItem* selectedItem = this->selectedItem();
	if(selectedItem == 0)
		return;
	
	selectedItem->beginChange();
	selectedItem->decreaseCompletion(1);
	selectedItem->endChange();
}

void ToDoList::incPriority()
{
	ToDoItem* selectedItem = this->selectedItem();
	if(selectedItem == 0)
		return;
	selectedItem->increasePriority(1);
}

void ToDoList::decPriority()
{
	ToDoItem* selectedItem = this->selectedItem();
	if(selectedItem == 0)
		return;
	
	selectedItem->decreasePriority(1);
}

// void ToDoList::updateToRootItem(QListViewItem* item)
// {
// 	ToDoItem* todoItem = dynamic_cast<ToDoItem*>(item);
// 	
// 	if(!todoItem)
// 		return;
// 	
// }

bool ToDoList::loadFromXMLFile(const QString& filename)
{	
	ToDoItem::stateChanging = true;
	QDomDocument domTree("outlines");
	
	QFile file (filename);
	if(!file.open(IO_ReadOnly))
	{
		QMessageBox::critical(0, tr("Critical error"), tr("Can't open file %1").arg(filename));
		return false;
	}
	
	QString error;
	int errorLine;
	int errorColumn;
	
	if(!domTree.setContent(&file, &error, &errorLine, &errorColumn))
	{
		QMessageBox::critical(0, tr("Critical error"), tr("%1 for file %2 \n(line = %3, column = %4)").arg(error).arg(filename).arg(errorLine).arg(errorColumn));
		file.close();
		return false;
	}
	file.close();
	
	clear();
	
	// get the header info from DOM
	QDomElement root = domTree.documentElement();
	QDomElement header;
	QDomNode node;
	node = root.firstChild();
	while ( !node.isNull() ) {
		if ( node.isElement() && node.nodeName() == "head" ) {
			header = node.toElement();
			getHeaderInfo( header );
			break;
		}
		node = node.nextSibling();
	}
	
	 // create the tree view out of the DOM
	node = root.firstChild();
	while ( !node.isNull() ) {
		if ( node.isElement() && node.nodeName() == "body" ) {
			QDomElement body = node.toElement();
			buildTree( 0, body );
			break;
		}
		node = node.nextSibling();
	}
	
	ToDoItem::stateChanging = false;

	return true;
}

void ToDoList::getHeaderInfo(const QDomElement& header)
{
	// visit all children of the header element and look if you can make
    // something with it
	QDomNode node = header.firstChild();
	while ( !node.isNull() ) {
		if ( node.isElement() ) {
            // case for the different header entries
			if ( node.nodeName() == "title" ) {
				QDomText textChild = node.firstChild().toText();
				if ( !textChild.isNull() ) {
					//_lstToDo->setColumnText( 0, textChild.nodeValue() );
				}
			}
		}
		node = node.nextSibling();
	}
}

void ToDoList::buildTree(ToDoItem* parentItem, const QDomElement& parentElement)
{
	//QListViewItem *thisItem = 0;
	ToDoItem* thisItem = 0;
	QDomNode node = parentElement.firstChild();
	while ( !node.isNull() ) {
		if ( node.isElement() && node.nodeName() == "outline" ) {
            // add a new list view item for the outline
			QString text = node.toElement().attribute( "text");
			int percents = node.toElement().attribute( "persent").toInt();
			int priority = node.toElement().attribute( "priority").toInt();
			bool isCompleted = (bool)node.toElement().attribute("completed").toInt();
			//QString content = node.toElement().text();
			
			if ( parentItem == 0 ){
				//thisItem = new ToDoItem( this, thisItem );
				thisItem = new ToDoItem(this, text );
			}
			else{
				thisItem = new ToDoItem( parentItem, text );
			}
			thisItem->setPercentComplete(percents);
			thisItem->setPriority(priority);
			thisItem->setRenameEnabled(0, true);
//			thisItem->setContent(content);
			if(isCompleted){
				//thisItem->setOn(true);
				thisItem->setState(QCheckListItem::On);
			}
			else 
				thisItem->setState(QCheckListItem::Off);
			//thisItem->setText( 0, node.toElement().attribute( "text" ) );
            // recursive build of the tree
			buildTree( thisItem, node.toElement() );
		}
		if(node.isText())
		{
 			QDomText t = node.toText();
			// todo: append content
			parentItem->setContent( t.data() );
		}
		node = node.nextSibling();
	}
}

bool ToDoList::saveToXMLFile(const QString& filename)
{
	QFile file(filename);
	if(!file.open(IO_WriteOnly))
	{
		QMessageBox::critical(0, tr("Write error"), tr("Can't open file %1").arg(filename) );
		return false;
	}
	
	QDomDocument domTree("outlines");
	
	
	QDomElement root = domTree.createElement("opml");
	QDomElement body = domTree.createElement("body");
	
	domTree.appendChild(root);
	root.appendChild(body);
	
	treeToXML(0, body);
	
	QTextStream stream(&file);
	stream.setEncoding(QTextStream::UnicodeUTF8);
	stream << domTree.toString();
	
	file.close();
	
	return true;
}

void ToDoList::updateToRootAll()
{
	
}

void ToDoList::headerToXML(const QDomElement& header)
{
}

void ToDoList::treeToXML(ToDoItem *parentItem, QDomElement& parentElement)
{
	ToDoItem* item;
	if(parentItem==0)
		item = dynamic_cast<ToDoItem*>(firstChild());
	else
		item = dynamic_cast<ToDoItem*>(parentItem->firstChild());

	while(item!=0)	
	{
		QDomElement childElement = parentElement.ownerDocument().createElement("outline");
		childElement.setAttribute("text", item->getName());
		childElement.setAttribute("persent", QString::number(item->getPercentComplete()));
		childElement.setAttribute("priority", QString::number(item->getPriority()));
		childElement.setAttribute("completed", QString::number((int)item->isOn()));
		QDomText content = parentElement.ownerDocument().createTextNode(item->getContent());
		childElement.appendChild(content);
//		childElement.setText(item->getContent());
		
		parentElement.appendChild(childElement);
		
		treeToXML(item, childElement);
			
		item = dynamic_cast<ToDoItem*>(item->nextSibling());
	}
}

// void ToDoList::paintEvent(QPaintEvent*)
// {
// 	
// }

void ToDoList::spacePressed(QListViewItem* item)
{
/* 	ToDoItem* todoItem = (ToDoItem*)item;
	todoItem->completeChildren(todoItem->isOn());
	todoItem->updateToRoot();*/
}

void ToDoList::editTask(QListViewItem* item)
{
	if(!selectedItem())
		return;
	
	frmEditTask* EditTaskForm = new frmEditTask(selectedItem());
	
	EditTaskForm->exec();
	
	delete EditTaskForm;
}

void ToDoList::completeAll()
{
	// completeBranch(root)
}

void ToDoList::completeBranch(QListViewItem* item)
{
	ToDoItem* todoItem = (item==0)? selectedItem() : (ToDoItem*)item;
	
	todoItem->setState(QCheckListItem::On);
	
	if(!todoItem)
		return;
	
	ToDoItem* child = (ToDoItem*)todoItem->firstChild();
	while(child!=0)
	{
		completeBranch(child);
		child = (ToDoItem*)child->nextSibling();
	}
}
		
/*void ToDoList::startDrag()
{
	QDragObject* d = Q
}*/
		
ToDoItem* ToDoList::selectedItem()
{
	return dynamic_cast<ToDoItem*>(QListView::selectedItem());
}

void ToDoList::contentsDragEnterEvent(QDragEnterEvent* e)
{
	e->accept(e->provides("text/x-task"));
}

void ToDoList::contentsDragMoveEvent(QDragMoveEvent* e)
{
}

void ToDoList::contentsDragLeaveEvent(QDragLeaveEvent* e)
{
	
}

void ToDoList::contentsDropEvent(QDropEvent* e)
{
	if(_dropItem!=0)
	{
		ToDoItem* i = dynamic_cast<ToDoItem*>(itemAt( this->contentsToViewport( e->pos()) ));
		if(i){
			i->insertItem(_dropItem);
			i->calculateParams();
			i->updateToRoot();
		}
		
		_dropItem =0;
	}
}

void ToDoList::startDrag()
{
	ToDoItem* i = this->selectedItem();
	if(i)
	{
		_dropItem = i;
		QListViewItem* parent = i->parent();
		
		if(parent){
			parent->takeItem(_dropItem);
			((ToDoItem*)parent)->calculateParams();
		}

		QTextDrag* drag = new QTextDrag(_dropItem->getContent(), this);
		drag->setSubtype("x-task");
		drag->setPixmap(QPixmap::fromMimeSource("data/identity.png"));
		drag->drag();
	}
}

void ToDoList::copyItem()
{
	_lastOperation = Copy;
	
	ToDoItem* todoItem = this->selectedItem();
	if(_bufferedItem)
		delete _bufferedItem;
	
/*	_bufferedItem = new ToDoItem(0, todoItem->getName());
	_bufferedItem->setContent(todoItem->getContent());
	_bufferedItem->*/
}

void ToDoList::cutItem()
{
	_lastOperation = Cut;
	
	ToDoItem* todoItem = this->selectedItem();
	
	if(_bufferedItem){
		delete _bufferedItem;
	}

	_bufferedItem = todoItem;
}

void ToDoList::pasteItem()
{
	ToDoItem* destItem = this->selectedItem();
	
	if(!_bufferedItem)
		return;
	
	if(destItem == _bufferedItem->parent() || !destItem)
		return;
	
	if(_lastOperation == Cut){
		ToDoItem* parent = (ToDoItem*)_bufferedItem->parent();
		
		if(parent){
			parent->takeItem(_bufferedItem);
			parent->calculateParams();
			parent->updateToRoot();
		}
		
		destItem->insertItem(_bufferedItem);
		destItem->calculateParams();
		destItem->updateToRoot();	
	}
	else if(_lastOperation == Copy)
	{
		// not implemented
	}
	
	_bufferedItem = 0;
	_lastOperation = None;

}
	